package com.example.demo.config.jwt;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.common.BaseResult;

import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;

/**
 * jwt验证类
 * 
 * @author Administrator
 *
 */
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

	public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
		super(authenticationManager);
	}

	/**
	 * 获取请求头的token
	 */
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		response.setContentType("application/json;charset=UTF-8"); // 响应类型

		String header = request.getHeader(JwtUtils.TOKEN_HEADER);

		// 如果请求头中没有Authorization信息则直接放行了
		if (header == null || !header.startsWith(JwtUtils.TOKEN_PREFIX)) {
			chain.doFilter(request, response);
			return;
		}

		// 如果请求头中有token，则进行解析，并且设置认证信息
		try {
			UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(header);

			/**
			 * 将Authentication用户验证，存入SecurityContext安全上下文，的子对象，安全上下文所有人，然后放行，否则令牌不正确
			 */
			SecurityContextHolder.getContext().setAuthentication(authenticationToken);
			chain.doFilter(request, response);

		} catch (JwtException e) {
			// 返回时，返回用户token
			BaseResult b = new BaseResult(200, "令牌不正确", null);
			// 拼接json串
			String jsonString = JSONObject.toJSONString(b);
			response.getWriter().write(jsonString);
		}
	}

	/**
	 * 这里从token中获取用户信息并新建一个token，新建了一个spring security的token
	 * 
	 * @throws Exception
	 */
	private UsernamePasswordAuthenticationToken getAuthentication(String header) throws JwtException {

		// 取出Bearer 后面的内容，即jwt令牌
		String token = header.replace(JwtUtils.TOKEN_PREFIX, "");

		// 这里有个验证失败的异常getUsername，在上面do拦截器时处理了
		String principal = JwtUtils.getUsername(token);
		if (principal != null) {
			// 主要的用户存入UsernamePasswordAuthenticationToken
			return new UsernamePasswordAuthenticationToken(principal, null, new ArrayList<>());
		}
		return null;
	}
}
